package com.flyqiu.flow.api.script;

import cn.hutool.core.convert.Convert;
import com.flyqiu.common.clazz.FlyQiuClassTools;
import com.flyqiu.common.tools.ConditionTools;
import com.flyqiu.common.tools.StringTools;
import com.flyqiu.flow.bpmn.base.ScriptModel;

import java.util.ArrayList;
import java.util.List;

public interface FlyQiuFlowScriptActuatorManage {
    /**
     * 脚本执行器
     *
     * @param flyQiuFlowScriptActuator 脚本执行器
     */
    void register(FlyQiuFlowScriptActuator flyQiuFlowScriptActuator);

    /**
     * 默认执行类型
     *
     * @return String
     */
    String getDefaultScriptActuatorType();

    /**
     * 设置脚本执行器类型
     *
     * @param scriptActuatorType 脚本执行器类型
     */
    void setDefaultScriptActuatorType(String scriptActuatorType);

    /**
     * 执行脚本
     *
     * @param script        待执行的脚本
     * @param variableScope 变量容器
     * @return Boolean
     */
    default boolean executeBooleanFullTrue(ScriptModel script, IVariableScope variableScope) {
        String scriptType = script.getScriptType();
        if (StringTools.isAllBlank(script.getScriptType())) {
            scriptType = getDefaultScriptActuatorType();
        }
        return executeBooleanFullTrue(scriptType, script.getScriptExpression(), variableScope);
    }


    /**
     * 执行脚本
     *
     * @param scriptType    脚本类型
     * @param script        脚本
     * @param variableScope 变量
     * @return boolean
     */
    default boolean executeBooleanFullTrue(String scriptType, String script, IVariableScope variableScope) {
        return execute(scriptType, script, variableScope, Boolean.class);
    }

    default <T> T execute(ScriptModel script, IVariableScope variableScope, Class<T> clazz) {
        String scriptType = script.getScriptType();
        if (StringTools.isAllBlank(script.getScriptType())) {
            scriptType = getDefaultScriptActuatorType();
        }
        return execute(scriptType, script.getScriptExpression(), variableScope, clazz);
    }

    @SuppressWarnings("unchecked")
    default <T> T execute(String scriptType, String script, IVariableScope variableScope, Class<T> returnType) {
        Object execute = execute(scriptType, script, variableScope);
        if (execute == null) {
            throw new RuntimeException("Executing  " + script + " script returns null value");
        }
        if (!FlyQiuClassTools.isForm(execute.getClass(), returnType)) {
            try {
                return Convert.convert(returnType, execute);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("The return value of executing the script:'" + script + "' cannot be converted to type :" + returnType);

            }
        }
        return (T) execute;
    }

    Object execute(String scriptType, String script, IVariableScope variableScope);


    /**
     * 脚本执行器
     *
     * @param script        脚本对象
     * @param variableScope 变量
     * @return 返回对象
     */
    default Object execute(ScriptModel script, IVariableScope variableScope) {
        String scriptType = script.getScriptType();
        if (StringTools.isBlank(script.getScriptType())) {
            scriptType = getDefaultScriptActuatorType();
        }
        return execute(scriptType, script.getScriptExpression(), variableScope);
    }

    @SuppressWarnings("checked")
    default boolean executeBooleanFullTrue(List<ScriptModel> scripts, IVariableScope variableScope) {
        List<Boolean> results = new ArrayList<>();
        for (ScriptModel script : scripts) {
            boolean execute = executeBooleanFullTrue(script, variableScope);
            results.add(execute);
        }
        return ConditionTools.eq(results);
    }

    default boolean executeBooleanHasTrue(List<ScriptModel> scripts, IVariableScope variableScope) {
        for (ScriptModel script : scripts) {
            boolean execute = executeBooleanFullTrue(script, variableScope);
            if (execute) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据脚本类型获取脚本执行器
     *
     * @param scriptType 脚本类型
     * @return 脚本执行器
     */
    FlyQiuFlowScriptActuator getScriptActuator(String scriptType);


}
